﻿/**************************************************************************
创建日期:	2023.3.22
作	  者:	张存
邮 	  箱:	zhangcunliang@126.com

描	述：简单的对象管理器，动态创建对象及默认值设定
记	录：
***************************************************************************/
using ASmile.Extend;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace ASmile.Object
{
    /// <summary>
    /// 对象工具
    /// </summary>
    public class ObjectTool
    {
        /// <summary>
        /// 资源对象列表
        /// </summary>
        public static Dictionary<string, ObjectConf> ResourceObjects { get; } = new Dictionary<string, ObjectConf>();
        /// <summary>
        /// key 程序集名称
        /// </summary>
        public static Dictionary<string, Assembly> AssemblyList { get; } = new Dictionary<string, Assembly>();
        /// <summary>
        /// 单例对象保存缓存
        /// </summary>
        static Dictionary<string, object> SingletonObjects { get; } = new Dictionary<string, object>();
        /// <summary>
        /// 反射创建对象
        /// </summary>
        public static object CreateObject(ObjectConf conf, Assembly asm = null)
        {
            if (asm == null)
            {
                asm = AssemblyList[conf.AssemblyName];
            }
            var type = asm.GetType(conf.TypeName, true, true);
            var obj = Activator.CreateInstance(type);
            if (conf.PropertyDefs?.Count > 0)
            {
                SetProperty(obj, conf.PropertyDefs);
            }
            return obj;
        }
        /// <summary>
        /// 设置对象属性值
        /// </summary>
        static void SetProperty(object obj, List<ObjectConfDef> propertys)
        {
            if (obj == null || propertys == null) return;

            foreach (var item in propertys)
            {
                if (item.PropertyName.IsEmpty()) continue;
                Type t = obj.GetType();
                var pro = t.GetProperty(item.PropertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                if (pro == null) continue;

                if (pro.PropertyType.IsClass && pro.PropertyType != typeof(string))
                {
                    if (item.SubProperty == null) continue;
                    var subObj = pro.GetValue(obj, null);
                    SetProperty(subObj, item.SubProperty);
                }
                else
                {
                    object pVal;
                    if (pro.PropertyType != typeof(string))
                    {
                        pVal = Convert.ChangeType(item.PropertyValue, pro.PropertyType);
                    }
                    else
                    {
                        pVal = item.PropertyValue;
                    }
                    pro.SetValue(obj, pVal, null);
                }
            }
        }
        /// <summary>
        /// 载入指定对象
        /// </summary>
        public static void LoadObject(List<ObjectConf> objList, Func<ObjectConf, bool> OnLoadBefore)
        {
            if (objList == null)
            {
                throw new Exception("要加载的对象列表为空");
            }
            foreach (var item in objList)
            {
                if (ResourceObjects.ContainsKey(item.Name))
                {
                    LogHelper.LogObj.Error($"服务名：{item.Name} 重复加载");
                    continue;
                }
                if (!AssemblyList.TryGetValue(item.AssemblyName, out Assembly asm))
                {
                    asm = Assembly.Load(item.AssemblyName);
                    AssemblyList[item.AssemblyName] = asm;
                }
                //这里概念错了，应该是false 预先创建对象
                if (item.LazyInit == true)
                {
                    item.Instance = CreateObject(item, asm);
                }

                if (OnLoadBefore != null)
                {
                    if (!OnLoadBefore(item)) continue;
                }

                ResourceObjects[item.Name] = item;
            }
        }
        /// <summary>
        /// 载入指定对象
        /// </summary>
        public static void LoadObject(List<ObjectConf> objList, Action<ObjectConf> OnLoadBefore)
        {
            LoadObject(objList, obj =>
            {
                OnLoadBefore(obj);
                return true;
            });
        }
        /// <summary>
        /// 载入指定对象
        /// </summary>
        public static void LoadObject(List<ObjectConf> objList)
        {
            LoadObject(objList, obj => { });
        }
        /// <summary>
        /// 获取对象
        /// </summary>
        public static object GetObject(string name)
        {
            if (!ResourceObjects.TryGetValue(name, out ObjectConf confObj))
            {
                return null;
            }
            if (confObj.Singleton == true)
            {
                if (!SingletonObjects.TryGetValue(name, out object obj))
                {
                    obj = CreateObject(confObj);
                    SingletonObjects[name] = obj;
                }
                return obj;
            }
            return CreateObject(confObj);
        }
        /// <summary>
        /// 获取泛型对象
        /// </summary>
        public static T GetObject<T>(string name) where T : class
        {
            var r = GetObject(name) as T;
            return r;
        }
    }
}